#ifndef _MESSAGE_H_
#define _MESSAGE_H_

#include <list>
#include <string>

#include <packet/Packet.h>


/**
 * Represents XMPP message packets. A message can be one of several types:
 *
 * <ul>
 *      <li>Message.Type.NORMAL -- (Default) a normal text message used in email like interface.
 *      <li>Message.Type.CHAT -- a typically short text message used in line-by-line chat interfaces.
 *      <li>Message.Type.GROUP_CHAT -- a chat message sent to a groupchat server for group chats.
 *      <li>Message.Type.HEADLINE -- a text message to be displayed in scrolling marquee displays.
 *      <li>Message.Type.ERROR -- indicates a messaging error.
 * </ul>
 *
 * For each message type, different message fields are typically used as follows:
 * <p>
 * <table border="1">
 * <tr><td>&nbsp;</td><td colspan="5"><b>Message type</b></td></tr>
 * <tr><td><i>Field</i></td><td><b>Normal</b></td><td><b>Chat</b></td><td><b>Group Chat</b></td><td><b>Headline</b></td><td><b>XMPPError</b></td></tr>
 * <tr><td><i>subject</i></td> <td>SHOULD</td><td>SHOULD NOT</td><td>SHOULD NOT</td><td>SHOULD NOT</td><td>SHOULD NOT</td></tr>
 * <tr><td><i>thread</i></td>  <td>OPTIONAL</td><td>SHOULD</td><td>OPTIONAL</td><td>OPTIONAL</td><td>SHOULD NOT</td></tr>
 * <tr><td><i>body</i></td>    <td>SHOULD</td><td>SHOULD</td><td>SHOULD</td><td>SHOULD</td><td>SHOULD NOT</td></tr>
 * <tr><td><i>error</i></td>   <td>MUST NOT</td><td>MUST NOT</td><td>MUST NOT</td><td>MUST NOT</td><td>MUST</td></tr>
 * </table>
 *
 * @author Matt Tucker
 */
class Message : public Packet {
public:
	class Body;
    /**
     * Represents the type of a message.
     */
    typedef enum {

        /**
         * (Default) a normal text message used in email like interface.
         */
		NORMAL,

        /**
         * Typically short text message used in line-by-line chat interfaces.
         */
		CHAT,

        /**
         * Chat message sent to a groupchat server for group chats.
         */
		GROUPCHAT,

        /**
         * Text message to be displayed in scrolling marquee displays.
         */
		HEADLINE,

        /**
         * indicates a messaging error.
         */
		ERROR
	} TYPE;

    /**
     * Creates a new, "normal" message.
     */
    Message() ;
	
    /**
     * Creates a new "normal" message to the specified recipient.
     *
     * @param to the recipient of the message.
     */
    Message(std::string to) ;

    /**
     * Creates a new message of the specified type to a recipient.
     *
     * @param to the user to send the message to.
     * @param type the message type.
     */
    Message(std::string to, TYPE type) ;
	
    /**
     * Returns the type of the message. If no type has been set this method will return {@link
     * org.jivesoftware.smack.packet.Message.Type#normal}.
     *
     * @return the type of the message.
     */
    TYPE getType() {
        return type;
    }

    /**
     * Sets the type of the message.
     *
     * @param type the type of the message.
     * @throws IllegalArgumentException if null is passed in as the type
     */
    void setType(TYPE type) {
		this->type = type;
	}

    /**
     * Returns the subject of the message, or null if the subject has not been set.
     * The subject is a short description of message contents.
     *
     * @return the subject of the message.
     */
	std::string getSubject() {
        return subject;
    }
	
    /**
     * Sets the subject of the message. The subject is a short description of
     * message contents.
     *
     * @param subject the subject of the message.
     */
    void setSubject(std::string subject) {
        this->subject = subject;
    }

    /**
     * Returns the body of the message, or null if the body has not been set. The body
     * is the main message contents.
     *
     * @return the body of the message.
     */
	std::string getBody() {
        return getBody(std::string(""));
    }

    /**
     * Returns the body corresponding to the language. If the language is null, the method result
     * will be the same as {@link #getBody()}. Null will be returned if the language does not have
     * a corresponding body.
     *
     * @param language the language of the body to return.
     * @return the body related to the passed in language.
     * @since 3.0.2
     */
	std::string getBody(std::string language);
	
    /**
     * Returns a set of all bodies in this Message, including the default message body accessible
     * from {@link #getBody()}.
     *
     * @return a collection of all bodies in this Message.
     * @since 3.0.2
     */
	std::list<Body*> getBodies();
	
    /**
     * Sets the body of the message. The body is the main message contents.
     *
     * @param body the body of the message.
     */
    void setBody(std::string & body);
	
    /**
     * Adds a body with a corresponding language.
     *
     * @param language the language of the body being added.
     * @param body the body being added to the message.
     * @return the new {@link org.jivesoftware.smack.packet.Message.Body}
     * @throws NullPointerException if the body is null, a null pointer exception is thrown
     * @since 3.0.2
     */
    Body * addBody(std::string & language, std::string & body);
	
    /**
     * Removes the body with the given language from the message.
     *
     * @param language the language of the body which is to be removed
     * @return true if a body was removed and false if it was not.
     */
    void removeBody(std::string language);
	
    /**
     * Removes the body from the message and returns true if the body was removed.
     *
     * @param body the body being removed from the message.
     * @return true if the body was successfully removed and false if it was not.
     * @since 3.0.2
     */
    void removeBody(Body * body);
	
    /**
     * Returns all the languages being used for the bodies, not including the default body.
     *
     * @return the languages being used for the bodies.
     * @since 3.0.2
     */
	std::list<std::string> getBodyLanguages();
	
    /**
     * Returns the thread id of the message, which is a unique identifier for a sequence
     * of "chat" messages. If no thread id is set, <tt>null</tt> will be returned.
     *
     * @return the thread id of the message, or <tt>null</tt> if it doesn't exist.
     */
	std::string getThread() ;

    /**
     * Sets the thread id of the message, which is a unique identifier for a sequence
     * of "chat" messages.
     *
     * @param thread the thread id of the message.
     */
    void setThread(std::string & thread) ;

    /**
     * Sets the xml:lang of this Message.
     *
     * @param language the xml:lang of this Message.
     * @since 3.0.2
     */
    void setLanguage(std::string language) ;
	
	std::string toXML();
	
	inline bool operator==( const Message & m) const
	{ return bodies == m.bodies && language == m.language && subject == m.subject && thread == m.thread && type == m.type;}
	
	int hashCode();
	    
	/**
     * Represents a message body, its language and the content of the message.
     */
    class Body {
	public:
		
        /**
         * Returns the language of this message body. If the language is null, then, no language
         * was specified.
         *
         * @return the language of this message body.
         */
		std::string getLanguage() {
			return DEFAULT_LANGUAGE == language ? "" : language;
		}
		        
		/**
         * Returns the message content.
         *
         * @return the content of the message.
         */
		std::string getMessage() {
            return message;
        }
		
		bool operator==( const Body & b) const
		{ return language == b.language && message == b.message; }
        
		int hashCode() { return 0;}

	private:
        Body(std::string & language, std::string & message) : 
			language(language),
			message(message)
		{}
		std::string message;
		std::string language;
	};


private:
    /**
     * Returns the xml:lang of this Message.
     *
     * @return the xml:lang of this Message.
     * @since 3.0.2
     */
	std::string getLanguage() {
        return language;
    }

    TYPE type;
	std::string subject;
	std::string thread;
	std::string language;
	std::list<Body*> bodies;
};

#endif // -- _MESSAGE_H_
